const fs = require('fs')
const Fn = require('./fn.js')
const startTime = Acan.time() // 进程启动时间
const fn = {
  errFn(code, message) {
    return { code, message }
  },
  notFound(get) {
    return { code: 404, message: `not found ${get._id}` }
  },
  nsNot(req) {
    return { code: 400, message: `not found ${req.ns}` }
  },
  getOpt(get) {
    const formats = {
      limit(d) { return parseInt(d || 10) },
      skip(d) { return parseInt(d || 0) },
      sort(d) {
        for (const k in d) {
          if (!d[k]) delete d[k]
          else d[k] = parseInt(d[k])
        }
        return d
      }
    }
    const opt = {}
    Acan.each(get, (v, k) => {
      if (k[0] === '$') {
        const ok = k.substr(1).split('[')[0]
        const fn = formats[ok]
        if (opt[ok]) opt[ok] = [opt[ok]], opt[ok].push(fn ? fn(v) : v)
        else opt[ok] = fn ? fn(v) : v
        delete get[k]
      }
    })
    if (opt.select && Acan.isStr(opt.select)) opt.select = [opt.select] 
    return opt
  }
}

const objPlus = (rs, o, pk) => {
  Acan.each(rs, (v, k) => {
    if (v !== 0 && k === 'table' && pk === 'total') return
    if (Acan.isInt(v)) rs[k] += o[k] || 0
    if (Acan.isObj(v)) objPlus(v, o[k], k)
  })
}
const mod = {
  async cpu(...args) {
    const rs = await Thm.cpu()
    args.pop()(rs)
  },
  async qps(...args) {
    const pids = Object.keys(qpsfork)
    rs = { mem: process.memoryUsage(), total: { table: 0, inc: 0, memSize: 0 } }
    pids.map(pid => {
      objPlus(rs, qpsfork[pid])
    })
    rs.cpus = await Thm.cpu()
    if (rs.cpus) delete rs.cpus.data
    args.pop()(Object.assign(rs, actRate))
  },
  async zstdRaw(...args) { // 压缩上上小时的文件为zstd
    args.pop()(await Fn.zstdRaw())
  },
  async restart(...args) { // 重启服务端
    proxy.io.close()
    proxy.close()
    Adebug.log('restart')
    Thm.proxy('restart', (rs) => {
      rs.message = 'ok'
      args.pop()(rs)
      setTimeout(() => { process.exit(0) }, 100)
    })
  },
  async tableList(get, ...args) {
    Thm.proxy('tableList', get, args.pop())
  },
  async hourList(get, req, ...args) { // 小时分片列表
    Thm.proxyTable('hourList', req.ns, get, args.pop())
  },
  async tableInfo(get, req, ...args) {
    Thm.proxyTable('tableInfo', req.ns, args.pop())
  },
  async index(...args) {
    args.pop()({ api: Object.keys(mod) })
  },
  async count(get, req, ...args) {
    const opt = fn.getOpt(get)
    Thm.proxyTable('count', req.ns, get, opt, args.pop())
  },
  async distinct(get, req, ...args) {
    const opt = fn.getOpt(get)
    Thm.proxyTable('distinct', req.ns, get, opt, args.pop())
  },
  async findOne(get, req, ...args) {
    const _t = Fn._t()
    const opt = fn.getOpt(get)
    Thm.proxyTable('findOne', req.ns, get, opt, (d) => {
      if (d.code) return args.pop()(Object.assign({ hs: Fn._t() - _t }, d))
      args.pop()({ hs: Fn._tf(Fn._t() - _t), offset: d[0], data: d[1] })
    })
  },
  async find(get, req, ...args) {
    const opt = fn.getOpt(get)
    Thm.proxyTable('find', req.ns, get, opt, args.pop())
  },
  async dbList(...args) {
    const dirs = fs.readdirSync(conf.db, { withFileTypes: true })
    const arr = []
    for (const dir of dirs) {
      if (dir.isDirectory) arr.push(dir)
    }
    args.pop()(arr)
  },
  async sysInfo(...args) {
    args.pop()(sysInfo(['pid', 'arch', 'cpu', 'avg', 'mem', 'uptime', 'version', 'network', 'cpus', 'os']))
  },
  async createTable(get, req, ...args) {
    const _t = Fn._t()
    const post = await req.data()
    Thm.proxy('createTable', post.ns, post.cols, post.opt, (rs) => {
      args.pop()({ hs: Fn._tf(Fn._t() - _t), ns: rs.ns, cols: rs.cols, opt: rs.opt, inc: rs.inc, hourList: rs.hourList, oldInc: rs.oldInc })
    })
  },
  async upTable(get, req, ...args) {
    const _t = Fn._t()
    const post = await req.data()
    Thm.proxyTable('upTable', req.ns, post.cols, post.opt, (rs) => {
      rs.hs = Fn._tf(Fn._t() - _t)
      args.pop()(rs)
    })
  },
  async create(get, req, ...args) {
    const _t = Fn._t()
    Thm.proxyTable('create', req.ns, await req.data(), (rs) => {
      rs.hs = Fn._tf(Fn._t() - _t)
      args.pop()(rs)
    })
  },
  async creates(get, req, ...args) {
    const _t = Fn._t()
    const post = await req.data()
    mod.create.inc += post.length
    if (Acan.isEmpty(post)) return args.pop()({ code: 500, message: 'empty post' })
    Thm.proxyTable('creates', req.ns, post, (rs) => {
      rs.hs = Fn._tf(Fn._t() - _t)
      args.pop()(rs)
    })
  },
  async update(get, req, ...args) {
    const _t = Fn._t()
    Thm.proxyTable('update', req.ns, get, (rs) => {
      rs.hs = Fn._tf(Fn._t() - _t)
      args.pop()(rs)
    })
  }
}

module.exports = mod
